﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CmdTemporaryShowHideElement.h"

#include "IUiDocument.h"
#include "GbmpUiPlatformCommandIds.h"
#include "ISelection.h"
#include "IUserTransaction.h"
#include "GbmpUiPlatformCommandRegister.h"
#include "IGraphicsNodeReference.h"
#include "IHighlights.h"


#include "IModelView.h"
#include "ILinkDocumentElement.h"
#include "ILinkElementProxy.h"
#include "UiDocumentViewUtils.h"
#include "GcmpCommandState.h"
#include "IGroup.h"
#include "IGenericElement.h"
#include "IDrawingTable.h"
#include "IElementBasicInformation.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "IElementViewSpecificShapeComponent.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace
{
    std::vector<const IGraphicsElementShape*> GetVisibleGrepsInModelViewWithoutCroppedByViewPort(const IModelView* pModelView)
    {
        std::vector<const IGraphicsElementShape*> visibleGRepsCache;
        DBG_WARN_AND_RETURN_UNLESS(pModelView, visibleGRepsCache, L"pModelView为空",L"GDMPLab",L"2024-03-30");

        const GraphicsElementShapes& visibleGRepCachesMap = pModelView->GetVisibleModelViewElementShapesWithoutCroppedByViewPort();
        for (auto pos = visibleGRepCachesMap.begin(); pos != visibleGRepCachesMap.end(); ++pos)
        {
            if (pos->second.Get() != nullptr)
            {
                visibleGRepsCache.push_back(pos->second.Get());
            }
        }
        return visibleGRepsCache;
    }
}


CmdTemporaryHideSelectedElements::CmdTemporaryHideSelectedElements(void)
    : CommandBase(ID_CMD_TEMPORARY_HIDE_SELECTION)
{
}

CmdTemporaryHideSelectedElements::~CmdTemporaryHideSelectedElements(void)
{
}

bool CmdTemporaryHideSelectedElements::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

bool CmdTemporaryHideSelectedElements::IsEnabled() const
{
    const GraphicsNodeReferenceOwnerPtrSet& selectedElems = ISelection::Get()->GetGraphicsNodeReferences();
    if ((int)selectedElems.size() != 0)
    {
        return true;
    }
   return false;
}

gcmp::OwnerPtr<IAction> CmdTemporaryHideSelectedElements::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IUiDocument* pUIDoc = UiDocumentViewUtils::GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUIDoc != nullptr, nullptr, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IModelView* pModelView = UiDocumentViewUtils::GetCurrentModelView();
    DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, nullptr, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    ElementId sectionBoxId = pModelView->GetSectionBoxId();

    {
        OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, GBMP_TR(L"隐藏选中物体"));
        DBG_WARN_AND_RETURN_UNLESS(ut, nullptr, L"事务创建失败",L"GDMPLab",L"2024-03-30");
        const GraphicsNodeReferenceOwnerPtrSet& selectedElems = ISelection::Get()->GetGraphicsNodeReferences();
        FOR_EACH(item, selectedElems)
        {
            ElementId eid = item->GetElementId();
            //对链接文档特殊处理
            IElement* pElement = pDoc->GetElement(eid);
            DBG_WARN_AND_RETURN_UNLESS(pElement, nullptr, L"pElement为空",L"GDMPLab",L"2024-03-30");
            ILinkDocumentElement* pLinkDocumentElement = dynamic_cast<ILinkDocumentElement*>(pElement);
            if (pLinkDocumentElement)
            {
                std::vector<ElementId> ProxyElementIds = pLinkDocumentElement->GetElementProxyIds();
                FOR_EACH(ProxyElementId, ProxyElementIds)
                {
                    if (eid != sectionBoxId)
                    {
                        pModelView->SetElementVisibilityByElementId(ProxyElementId, false);
                    }
                }
            }
            if (eid == sectionBoxId)
                continue;
            pModelView->SetElementVisibilityByElementId(eid, false);
        }
        ISelection::Get()->Clear(pDoc);
        IHighlights::Get()->Clear();        
        bool bCommit = ut->Commit();
        DBG_WARN_AND_RETURN_UNLESS(bCommit, nullptr, L"事务提交失败",L"GDMPLab",L"2024-03-30");
    }
    
    pUIDoc->UpdateViewByVisibilityConditionChanged();
    return nullptr;
}
REGISTER_GM_COMMAND(CmdTemporaryHideSelectedElements);
//////////////////////////////////////////////////////////////////////////


CmdTemporaryHideOtherElements::CmdTemporaryHideOtherElements(void)
: CommandBase(ID_CMD_TEMPORARY_HIDE_OTHER)
{
}

CmdTemporaryHideOtherElements::~CmdTemporaryHideOtherElements(void)
{
}

bool CmdTemporaryHideOtherElements::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

bool CmdTemporaryHideOtherElements::IsEnabled() const
{
    const GraphicsNodeReferenceOwnerPtrSet& selectedElems = ISelection::Get()->GetGraphicsNodeReferences();
    if ((int)selectedElems.size() != 0)
    {
        return true;
    }
    return false;
}

gcmp::OwnerPtr<IAction> CmdTemporaryHideOtherElements::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IUiDocument* pUIDoc = UiDocumentViewUtils::GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUIDoc != nullptr, nullptr, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IModelView* pModelView = UiDocumentViewUtils::GetCurrentModelView();
    DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, nullptr, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    ElementId sectionBoxId = pModelView->GetSectionBoxId();

    {
        OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, GBMP_TR(L"隐藏选中以外其他物体"), true);
        DBG_WARN_AND_RETURN_UNLESS(ut, nullptr, L"事务创建失败",L"GDMPLab",L"2024-03-30");
        std::vector<const IGraphicsElementShape*> allViewGreps = GetVisibleGrepsInModelViewWithoutCroppedByViewPort(pModelView);
        const GraphicsNodeReferenceOwnerPtrSet& selectedElems = ISelection::Get()->GetGraphicsNodeReferences();
        FOR_EACH(item, selectedElems)
        {
            //对链接文档特殊处理
            ElementId eid = item->GetElementId();
            IElement* pElement = pDoc->GetElement(eid);
            DBG_WARN_AND_RETURN_UNLESS(pElement, nullptr, L"pElement为空",L"GDMPLab",L"2024-03-30");
            ILinkDocumentElement* pLinkDocumentElement = dynamic_cast<ILinkDocumentElement*>(pElement);
            if (pLinkDocumentElement)
            {
                std::vector<ElementId> ProxyElementIds = pLinkDocumentElement->GetElementProxyIds();
                FOR_EACH(ProxyElementId, ProxyElementIds)
                {
                    const IGraphicsElementShape* pGraphicsElementShape = pModelView->GetModelViewElementShape(ProxyElementId);
                    auto iter = find(allViewGreps.begin(), allViewGreps.end(), pGraphicsElementShape);
                    if (iter != allViewGreps.end())
                    {
                        allViewGreps.erase(iter);
                    }
                }
            }
            ILinkElementProxy* pLinkElementProxy = dynamic_cast<ILinkElementProxy*>(pElement);
            if (pLinkElementProxy)
            {
                const ILinkDocumentElement* pLinkDocumentElement = pLinkElementProxy->GetLinkDocumentElement();
                const IGraphicsElementShape* pGraphicsElementShape = pModelView->GetModelViewElementShape(pLinkDocumentElement->GetElementId());
                auto iter = find(allViewGreps.begin(), allViewGreps.end(), pGraphicsElementShape);
                if (iter != allViewGreps.end())
                {
                    allViewGreps.erase(iter);
                }
            }

            if (const IGroup* pGroup = quick_cast<const IGroup>(pElement))
            {
                UnorderedElementIdSet subElementIds;
                pGroup->GetAllElementIdsInGroup(subElementIds);
                FOR_EACH(subId, subElementIds)
                {
                    const IGraphicsElementShape* pGrep = pModelView->GetModelViewElementShape(subId);
                    auto iter = find(allViewGreps.begin(), allViewGreps.end(), pGrep);
                    if (iter != allViewGreps.end())
                    {
                        allViewGreps.erase(iter);
                    }
                }                
            }

            //针对表格的特殊处理,需要移除当前表格的所有item
            IElementBasicInformation *pElementBasicInformation = pElement->GetBasicInformation();
            if (pElementBasicInformation != nullptr
                && (pElementBasicInformation->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DRAWING_TABLE_ELEMENT 
                    || pElementBasicInformation->GetClassficationUid() == GuidUtils::FromString(L"{EDBC1DCC-7BC6-4EE1-BD90-0880B2E3E5C8}")))
            {
                const IElementViewSpecificShapeComponent* pViewSpecific = pElement->GetViewSpecificShapeComponent();
                if (pViewSpecific == nullptr)
                    continue;
               
                ElementId tableElementId;
                std::vector<ElementId> hostElements;
                pViewSpecific->ReportDependentElements(hostElements);
                if (!hostElements.empty())
                    tableElementId = hostElements[0];
                else
                    tableElementId = eid;

                IElement* pTableElement = pDoc->GetElement(tableElementId);
                if (pTableElement == nullptr)
                    continue;

                IGenericElement* pTableGenericElement = quick_cast<IGenericElement>(pTableElement);
                if (pTableGenericElement == nullptr)
                    continue;

                IDrawingTable* pDrawingTable = quick_cast<IDrawingTable>(pTableGenericElement->GetExternalObject());
                if (pDrawingTable == nullptr)
                    continue;

                std::set<ElementId> elementIdSet = pDrawingTable->GetTableItemIds();
                elementIdSet.insert(tableElementId);
                FOR_EACH(subId, elementIdSet)
                {
                    const IGraphicsElementShape* pGrep = pModelView->GetModelViewElementShape(subId);
                    auto iter = find(allViewGreps.begin(), allViewGreps.end(), pGrep);
                    if (iter != allViewGreps.end())
                    {
                        allViewGreps.erase(iter);
                    }
                }
            }
        }

        FOR_EACH(item, allViewGreps)
        {
            ElementId elementId = item->GetElementId();
            if (!OwnerPtrContainerUtil::IsInContainer(selectedElems, IGraphicsNodeReference::CreateGraphicsElementShapeReference(elementId)))
            {
                if (elementId == sectionBoxId)
                    continue;
                pModelView->SetElementVisibilityByElementId(elementId, false);
            }  
        }
        ISelection::Get()->Clear(pDoc);
        IHighlights::Get()->Clear();
        bool bCommit = ut->Commit();
        DBG_WARN_AND_RETURN_UNLESS(bCommit, nullptr, L"事务提交失败",L"GDMPLab",L"2024-03-30");
    }

    pUIDoc->UpdateViewByVisibilityConditionChanged();
    return nullptr;
}
REGISTER_GM_COMMAND(CmdTemporaryHideOtherElements);
//////////////////////////////////////////////////////////////////////////

CmdResetTemporaryHiddenElements::CmdResetTemporaryHiddenElements(void)
    : CommandBase(ID_CMD_RESET_TEMPORARY_HIDDEN_ELEMENTS)
{
}

CmdResetTemporaryHiddenElements::~CmdResetTemporaryHiddenElements(void)
{
}



bool CmdResetTemporaryHiddenElements::IsVisible() const
{
    return GcmpCommandState::IsInFamilyEnvironment() || 
        GcmpCommandState::IsInProjectEnvironment() ||
        GcmpCommandState::IsInAnimationEnvironment();
}

bool CmdResetTemporaryHiddenElements::IsEnabled() const
{
    return GcmpCommandState::IsInFamilyEnvironment() ||
        GcmpCommandState::IsInProjectEnvironment() ||
        GcmpCommandState::IsInAnimationEnvironment();
}

gcmp::OwnerPtr<IAction> CmdResetTemporaryHiddenElements::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IUiDocument* pUIDoc = UiDocumentViewUtils::GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUIDoc != nullptr, nullptr, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IModelView* pModelView = UiDocumentViewUtils::GetCurrentModelView();
    DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, nullptr, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    ElementId sectionBoxId = pModelView->GetSectionBoxId();

    {
        OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, GBMP_TR(L"隐藏选中物体"), true);
        DBG_WARN_AND_RETURN_UNLESS(ut, nullptr, L"事务创建失败",L"GDMPLab",L"2024-03-30");

        const std::set<ElementId> invisibleElementIds = pModelView->GetInvisibleElementsSetByElementId();
        for (const auto &elementId : invisibleElementIds)
        {
            if (elementId == sectionBoxId)
                continue;
            pModelView->SetElementVisibilityByElementId(elementId, true);
        }

        bool bCommit = ut->Commit();
        DBG_WARN_AND_RETURN_UNLESS(bCommit, nullptr, L"事务提交失败",L"GDMPLab",L"2024-03-30");
    }

    pUIDoc->UpdateViewByVisibilityConditionChanged();
    return nullptr;
}
REGISTER_GM_COMMAND(CmdResetTemporaryHiddenElements)


